import { Vec3, math } from 'cc';
import { Game } from '../core/Game';
import { Databus } from '../core/Databus';
import { BilliardGame } from '../game/BilliardGame';
import { BallAttribute } from '../core/BallAttribute';
import { WebFrameSimulation } from './WebFrameSimulation';
import { WebFrameCollection } from './WebFrameCollection';
import { SendWebSocket } from '../websocket/SendWebSocket';
import { EndStepSyncFrame, NetHitMainBallFrame, NetKeyFrame } from '../core/WebSocketData';
const databus = Databus.Instance();

export class WebFrameController {
  private static instance: WebFrameController = null as unknown as WebFrameController;
  public frameSimulation = new WebFrameSimulation();
  public frameCollection = new WebFrameCollection();
  public isFinishedFrame = false;
  public stepEndData = null;
  // 每3秒钟发送一次心跳
  private heartBeatTime = 0;
  public static Instance() {
    if (WebFrameController.instance) {
      return WebFrameController.instance;
    }
    WebFrameController.instance = new WebFrameController();
    return WebFrameController.instance;
  }
  constructor() { }
  public startGame() {
    this.frameCollection.startGame();
    this.frameSimulation.startGame();
    this.isFinishedFrame = false;
    this.stepEndData = null;
  }
  public startStepFrame() {
    this.frameCollection.startCollectFrame();
    this.frameSimulation.startSimulate();
    this.isFinishedFrame = false;
  }

  public endStepFrame() {
    this.frameCollection.endCollectFrame();
    this.frameSimulation.endSimulate();
    this.sendSyncStepOver();
  }

  public updateFrame(deltaTime: number) {
    // 非好友对战，则直接返回
    if (!Game.Instance().battleCate.isFrientBattle()) return;
    // 自己击球，发送帧数据
    if (Game.Instance().isSelftHitBall()) {
      this.frameCollection.collectSendFrame(deltaTime);
    } else { // 对手击球，模拟帧数据
      this.frameSimulation.updateSimulateFrame(deltaTime);
    }
    this.updateAskConfirm(); // 要求对方重新发送数据
    // 3秒发一次心跳，重新连接上服务器
    const mt = Date.now();
    if (mt - this.heartBeatTime > 3000) {
      this.heartBeatTime = mt;
      new SendWebSocket().heartRequst();
    }
  }

  // 快速追赶上当前帧的数据
  public fastCatchStepFrame(step: number, frame: NetKeyFrame) {
    console.log('fast catch step frame ', frame);
    Game.Instance().currentStep = step;
    BilliardGame.Instance().currentTimestamp = Date.now() - frame.timestamp - 10;
    BilliardGame.Instance().currentFrameSeq = frame.seq - 1;
    this.frameSimulation.restartRecvFrame();
    this.frameSimulation.addKeyFrame(frame);
    BilliardGame.Instance().actionStage.forceFinished();
  }
  // 快速对齐最后一帧的状态数据，准备进行下一杆击球
  public fastSyncEndFrame(endStepFrame: EndStepSyncFrame) {
    console.log('fast sync end frame ', endStepFrame);
    this.stepEndData = endStepFrame;
    Game.Instance().currentStep = endStepFrame.step;
    // 扭转状态到待确认
    BilliardGame.Instance().actionStage.waitConfirm(); // 即可之间进行当前step的结束计算逻辑
  }
  // 对齐首帧数据
  public sendGameFirstFrame() {
    // 非好友对战，则直接返回
    if (!Game.Instance().battleCate.isFrientBattle()) return;
    // 自己击球，发送帧数据
    if (Game.Instance().isSelftHitBall()) {
      const frame = this.frameCollection.collectCurrentFrame();
      new SendWebSocket().sendGameFirstFrame(frame);
    }
  }
  public sendSyncStepOver() {
    if (!Game.Instance().battleCate.isFrientBattle()) return;
    // 自己击球，发送帧数据
    if (Game.Instance().isSelftHitBall()) {
      var firstBallName = '';
      if (BilliardGame.Instance().firstCollideBall) {
        firstBallName = BilliardGame.Instance().firstCollideBall.ballName();
      }
      const hitBallList = Game.Instance().hitBallList.filter(hb => hb.step === Game.Instance().currentStep);
      const hitBallListName = hitBallList.map(item => item.ba.ballName());
      const endFrame = this.frameCollection.collectEndFrame();
      this.stepEndData = new EndStepSyncFrame(
        Game.Instance().currentStep, firstBallName, endFrame, hitBallListName,
      );
      new SendWebSocket().sendSyncStepOver(this.stepEndData);
      console.log('send sync last step frame ');
    }
  }
  public updateAskConfirm() {
    if (BilliardGame.Instance().currentFrameSeq % 100 !== 0) return;
    if (Game.Instance().isSelftHitBall()) return;
    // 对齐信号
    if (BilliardGame.Instance().actionStage.isExceptionStage()) {
      new SendWebSocket().sendAskConfirm(Game.Instance().currentStep, 0, 0);
    }
    return;
  }
  // 发送击打白球信息
  public sendHitMainBall(pos: Vec3, vel: Vec3, sop: Vec3) {
    const hitMainBallFrame = new NetHitMainBallFrame();
    hitMainBallFrame.setMainBall(pos, vel, sop);
    const step = Game.Instance().currentStep;
    const balls = BilliardGame.Instance().getAllBallList();
    hitMainBallFrame.setKeyFrame(step, 0, 0, 0, balls);
    new SendWebSocket().sendMainBallHitted(hitMainBallFrame);
  }
  public resendStepOverData(step: number) {
    if (this.stepEndData) {
      if (step <= this.stepEndData.step) {
        console.log('resend step over data ', this.stepEndData);
        new SendWebSocket().sendSyncStepOver(this.stepEndData);
      }
    }
  }
  // 在扭转下一步之前，先对齐保证相关数据的一致性
  public syncStepOverData() {
    // 说明已经走到WaitConfirm状态，等待计算当前步的结果
    // 收到syncstepover数据，且已经模拟完成最后一帧的数据
    if (!this.stepEndData) {
      return false;
    }
    if (this.stepEndData.step !== Game.Instance().currentStep) {
      return false;
    }
    // 1. 最先击打到的球
    const fb = BallAttribute.getBallByName(this.stepEndData.firstHitBallName);
    BilliardGame.Instance().firstCollideBall = fb;
    // 2. 最后一帧数据, 放入队列进行模拟
    WebFrameController.Instance().frameSimulation.simulateFrame(this.stepEndData.endFrame);
    WebFrameController.Instance().frameSimulation.addKeyFrame(this.stepEndData.endFrame);
    // 3. 进球列表，需要对齐
    Game.Instance().checkHitBallList(this.stepEndData.step, this.stepEndData.hitBallListName);

    return true;
  }
}

